package xmlMapping.lts;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class InstrumentPoolRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    private String instrumentPoolId;
    private String symbol;
    private double qty;
    private double buyHeld;
    private double sellHeld;
    private String route;
    private String operator;
    private Date updateTime;
    // k = AccountId
    private Map<String, SharedInstrumentPoolHeld> accountPoolHeldMap = new ConcurrentHashMap<>();
    private InstrumentPool instrumentPool;

    public String getInstrumentPoolId() {
        return instrumentPoolId;
    }

    public void setInstrumentPoolId(String instrumentPoolId) {
        this.instrumentPoolId = instrumentPoolId;
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public double getQty() {
        return qty;
    }

    public void setQty(double qty) {
        this.qty = qty;
    }

    public double getBuyHeld() {
        return buyHeld;
    }

    public void setBuyHeld(double buyHeld) {
        this.buyHeld = buyHeld;
    }

    public double getSellHeld() {
        return sellHeld;
    }

    public void setSellHeld(double sellHeld) {
        this.sellHeld = sellHeld;
    }

    // 未指定账户
    public double getBuyRemaining() {
        switch (instrumentPool.getType()) {
            case PRIVATE:
                return this.qty - this.buyHeld;
            case SHARED:
                return this.qty - getSumMaxHeld();
            default:
                return 0;
        }
    }

    // 该账户可买
    public double getBuyRemaining(String account) {
        switch (getInstrumentPoolType()) {
            case PRIVATE:
                return this.qty - this.buyHeld;
            case SHARED:
                return getSharedRemaining(account, OrderSide.Buy);
            default:
                return 0;
        }
    }

    // 未指定账户
    public double getSellRemaining() {
        switch (instrumentPool.getType()) {
            case PRIVATE:
                return this.qty - this.sellHeld;
            case SHARED:
                return this.qty - getSumMaxHeld();
            default:
                return 0;
        }
    }

    // 该账户可卖
    public double getSellRemaining(String account) {
        switch (getInstrumentPoolType()) {
            case PRIVATE:
                return this.qty - this.sellHeld;
            case SHARED:
                return getSharedRemaining(account, OrderSide.Sell);
            default:
                return 0;
        }
    }

    private double getSharedRemaining(String account, OrderSide side) {
        // 自己占用仓位
        SharedInstrumentPoolHeld held = accountPoolHeldMap.get(account);
        if (held == null) {
            return this.qty - getSumMaxHeld();
        }
        switch (side) {
            case Buy: {
                if (held.getPosition() < 0) {
                    return this.qty - getSumMaxHeld() + Math.abs(held.getPosition());
                } else {
                    return this.qty - getSumMaxHeld();
                }
            }
            case Sell: {
                if (held.getPosition() > 0) {
                    return this.qty - getSumMaxHeld() + held.getPosition();
                } else {
                    return this.qty - getSumMaxHeld();
                }
            }
            default:
                return 0;
        }
    }

    private double getSumMaxHeld() {
        return accountPoolHeldMap.values().stream()
                .map(SharedInstrumentPoolHeld::getMaxHeld)
                .reduce((sum, maxHeld) -> sum + maxHeld).orElse(0d);
    }

    public void addBuyHeld(String account, double held) {
        buyHeld += held;
        if (getInstrumentPoolType() == InstrumentPoolType.SHARED) {
            SharedInstrumentPoolHeld sharedHeld = accountPoolHeldMap.computeIfAbsent(account, k ->
                    new SharedInstrumentPoolHeld(instrumentPoolId, symbol, account, this.getRoute()));
            sharedHeld.addBuyHeld(held);
        }
    }

    public void addSellHeld(String account, double held) {
        sellHeld += held;
        if (getInstrumentPoolType() == InstrumentPoolType.SHARED) {
            SharedInstrumentPoolHeld sharedHeld = accountPoolHeldMap.computeIfAbsent(account, k ->
                    new SharedInstrumentPoolHeld(instrumentPoolId, symbol, account, this.getRoute()));
            sharedHeld.addSellHeld(held);
        }
    }

    public String getRoute() {
        return route;
    }

    public void setRoute(String route) {
        this.route = route;
    }

    public String getOperator() {
        return operator;
    }

    public void setOperator(String operator) {
        this.operator = operator;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public InstrumentPool getInstrumentPool() {
        return instrumentPool;
    }

    public void setInstrumentPool(InstrumentPool instrumentPool) {
        this.instrumentPool = instrumentPool;
    }

    public InstrumentPoolType getInstrumentPoolType() {
        return instrumentPool.getType();
    }

    public String getInstrumentPoolName() {
        return this.instrumentPool.getName();
    }

    public Set<String> getAccounts() {
        return getInstrumentPool().getAccounts();
    }

    public Map<String, SharedInstrumentPoolHeld> getAccountPoolHeldMap() {
        return accountPoolHeldMap;
    }

    public void setAccountPoolHeldMap(Map<String, SharedInstrumentPoolHeld> accountPoolHeldMap) {
        this.accountPoolHeldMap = accountPoolHeldMap;
    }

    @Override
    public String toString() {
        return "InstrumentPoolRecord{" +
                "instrumentPoolId='" + instrumentPoolId + '\'' +
                ", symbol='" + symbol + '\'' +
                ", qty=" + qty +
                ", route='" + route + '\'' +
                ", operator='" + operator + '\'' +
                '}';
    }
}
